/**
 ***************************************************************************************************
 *
 * @file    app_task.c
 *
 * @brief   RW APP Task implementation
 *
 * Copyright (C) Eker 2021
 *
 ***************************************************************************************************
 */

/**
 ***************************************************************************************************
 * @addtogroup APP
 * @{
 ***************************************************************************************************
 */

/*
 * INCLUDE FILES
 ***************************************************************************************************
 */
#include "ty_ble.h"
#include "app.h"

#define APP_LOG_DOMAIN      "app"
#define APP_LOG_LEVEL       APP_LOG_LEVEL_APP
#include "app_log.h"
#include "rwip_config.h"  

/*
 * LOCAL FUNCTION DEFINITIONS
 ***************************************************************************************************
 */
static uint8_t app_get_handler(const struct app_subtask_handlers *handler_list_desc,
                               ke_msg_id_t msgid,
                               void *param,
                               ke_task_id_t src_id)
{
    uint8_t counter;

    // Get the message handler function by parsing the message table
    for (counter = handler_list_desc->msg_cnt; 0 < counter; counter--)
    {
        struct ke_msg_handler *handler
               = (struct ke_msg_handler*)(handler_list_desc->p_msg_handler_tab + counter - 1);

        if ((handler->id == msgid) || (handler->id == KE_MSG_DEFAULT_HANDLER))
        {
            // If handler is NULL, message should not have been received in this state
            ASSERT_ERR(handler->func);

            return (uint8_t)(handler->func(msgid, param, TASK_APP, src_id));
        }
    }

    // If we are here no handler has been found, drop the message
    return (KE_MSG_CONSUMED);
}

/*
 * MESSAGE HANDLERS
 ***************************************************************************************************
 */
/**
 ***************************************************************************************************
 * @brief KE_MSG_DEFAULT_HANDLER handler
 *        Handles reception of all messages sent from the lower layers to the application
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int appm_msg_handler(ke_msg_id_t const msgid,
                            void *param,
                            ke_task_id_t const dest_id,
                            ke_task_id_t const src_id)
{
    // Retrieve identifier of the task from received message
    ke_task_id_t src_task_id = MSG_T(msgid);
    // Message policy
    uint8_t msg_pol = KE_MSG_CONSUMED;

    switch (src_task_id)
    {
        case (TASK_ID_GAPC):
        {
        #if (BLE_APP_SEC)
            if ((msgid >= GAPC_BOND_CMD) && (msgid <= GAPC_SECURITY_IND))
            {
                // Call the Security Module
                msg_pol = app_get_handler(&app_sec_handlers, msgid, param, src_id);
            }
        #endif
        } break;

        case (TASK_ID_GATTC):
        {
            // Service Changed - Drop
        #if (BLE_APP_CENTRAL_SUPPORT)
            msg_pol = app_get_handler(&app_gattc_handlers, msgid, param, src_id);
        #endif
        } break;

        // tuya
        case (TASK_ID_TYS):
        {
            msg_pol = app_get_handler(&app_ty_server_handlers, msgid, param, src_id);
        } break;

        default:
        {
        } break;
    }

    return (msg_pol);
}

/**
 ***************************************************************************************************
 * @brief GAPM_PROFILE_ADDED_IND handler
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance.
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapm_profile_added_ind_handler(ke_msg_id_t const msgid,
                                          struct gapm_profile_added_ind *param,
                                          ke_task_id_t const dest_id,
                                          ke_task_id_t const src_id)
{
    ke_state_t state = ke_state_get(dest_id);

    if (state == APPM_CREATE_DB)
    {
        switch (param->prf_task_id)
        {
            default:
                break;
        }
    }
    else
    {
        ASSERT_INFO(0, state, src_id);
    }
    return KE_MSG_CONSUMED;
}

/**
 ***************************************************************************************************
 * @brief GAPM_ACTIVITY_CREATED_IND handler
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance.
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapm_activity_created_ind_handler(ke_msg_id_t const msgid,
                                             struct gapm_activity_created_ind const *p_param,
                                             ke_task_id_t const dest_id,
                                             ke_task_id_t const src_id)
{
    if (p_param->actv_type == GAPM_ACTV_TYPE_ADV)
    {
        app_adv_created_ind_handler(p_param);
    }

#if (BLE_APP_CENTRAL_SUPPORT)
    else if (p_param->actv_type == GAPM_ACTV_TYPE_SCAN || p_param->actv_type == GAPM_ACTV_TYPE_INIT)
    {
        app_central_update_state(p_param->actv_type, p_param->actv_idx, 0);
    }
#endif

    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPM_ACTIVITY_STOPPED_IND handler
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance.
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapm_activity_stopped_ind_handler(ke_msg_id_t const msgid,
                                             struct gapm_activity_stopped_ind const *p_param,
                                             ke_task_id_t const dest_id,
                                             ke_task_id_t const src_id)
{
    if (p_param->actv_type == GAPM_ACTV_TYPE_ADV)
    {
        app_adv_stopped_ind_handler(p_param);
    }

#if (BLE_APP_CENTRAL_SUPPORT)
    else if (p_param->actv_type == GAPM_ACTV_TYPE_SCAN || p_param->actv_type == GAPM_ACTV_TYPE_INIT)
    {
        app_central_update_state(p_param->actv_type, p_param->actv_idx, p_param->reason);
    }
#endif

    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPM_CMP_EVT handler
 *        GAP manager command complete events.
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance (TASK_GAP).
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapm_cmp_evt_handler(ke_msg_id_t const msgid,
                                struct gapm_cmp_evt const *param,
                                ke_task_id_t const dest_id,
                                ke_task_id_t const src_id)
{
    switch(param->operation)
    {
        // Reset completed
        case (GAPM_RESET):
        {
            LOG_DBG("GAPM_RESET");
            if(param->status == GAP_ERR_NO_ERROR)
            {
                // Set Device configuration
                struct gapm_set_dev_config_cmd* cmd = KE_MSG_ALLOC(GAPM_SET_DEV_CONFIG_CMD,
                                                                   TASK_GAPM,
                                                                   TASK_APP,
                                                                   gapm_set_dev_config_cmd);
                // Set the operation
                cmd->operation = GAPM_SET_DEV_CONFIG;

                // Set the device role - Peripheral
            #if (BLE_APP_CENTRAL_SUPPORT)
                cmd->role = GAP_ROLE_ALL;
            #else
                cmd->role = GAP_ROLE_PERIPHERAL;
            #endif

                // Do not support secure connections
                cmd->pairing_mode = GAPM_PAIRING_LEGACY;

                // Set Data length parameters
                cmd->sugg_max_tx_octets = BLE_MAX_OCTETS;
                cmd->sugg_max_tx_time = BLE_MAX_TIME;

                // Preferred LE PHY for data transmission (@see enum gap_phy)
                cmd->tx_pref_phy = GAP_PHY_LE_2MBPS;

                // Preferred LE PHY for data reception (@see enum gap_phy)
                cmd->rx_pref_phy = GAP_PHY_LE_2MBPS;

                // Maximal MTU/MPS acceptable for device
                cmd->max_mtu = TY_GAP_LE_MTU;
                cmd->max_mps = TY_GAP_LE_MTU;

                // Host privacy disabled by default
                // cmd->privacy_cfg = GAPM_PRIV_CFG_PRIV_ADDR_BIT;
                memcpy(cmd->addr.addr, app_env.addr.addr.addr, BD_ADDR_LEN);
                log_debug_array_ex("[OM] set addr", app_env.addr.addr.addr, 6);

            #if ((NVDS_SUPPORT) && (BLE_APP_SEC))
                uint8_t key_len = KEY_LEN;
                if ((app_sec_get_bond_status()==true) &&
                    (nvds_get(NVDS_TAG_LOC_IRK, &key_len, app_env.loc_irk) == NVDS_OK))
                {
                    memcpy(cmd->irk.key, app_env.loc_irk, KEY_LEN);
                }
                else
            #endif
                {
                    memset((void *)&cmd->irk.key[0], 0x00, KEY_LEN);
                }

            #if (BLE_APP_PRIVACY)
                cmd->privacy_cfg |= GAPM_PRIV_CFG_PRIV_EN_BIT;
                cmd->renew_dur = 0x0384;
            #endif

                // Send message
                ke_msg_send(cmd);
            }
            else
            {
                ASSERT_ERR(0);
            }
        } break;

        // Device Configuration updated
        case (GAPM_SET_DEV_CONFIG):
        {
        #if (BLE_APP_WHITE_LIST)
            appm_whl_cmp_evt_handler(msgid, param, dest_id, src_id);
        #endif
        #if (BLE_APP_PRIVACY)
            appm_privacy_cmp_evt_handler(msgid, param, dest_id, src_id);
        #endif
        #if(BLE_APP_SEC)
            app_gap_set_local_irk();
        #endif
        #if (BLE_APP_WHITE_LIST==0 && BLE_APP_PRIVACY==0)
            ASSERT_INFO(param->status == GAP_ERR_NO_ERROR, param->operation, param->status);
            appm_reg_svc_itf();
            // Add the first required service in the database
            // and wait for the PROFILE_ADDED_IND
            appm_add_svc();
        #endif
        } break;

    #if (BLE_APP_WHITE_LIST)
        case (GAPM_GET_WLIST_SIZE):
        case (GAPM_SET_WL):
        {
            if(appm_whl_cmp_evt_handler(msgid, param, dest_id, src_id) != KE_MSG_CONSUMED)
            {
                ke_state_t state = ke_state_get(dest_id);

                if (state < APPM_READY) {
                    appm_reg_svc_itf();
                    appm_add_svc();
                }
            }
        } break;
    #endif

        case (GAPM_PROFILE_TASK_ADD):
        {
            LOG_DBG("GAPM_PROFILE_TASK_ADD");
            // Add the next requested service
            if (!appm_add_svc())
            {
                ke_state_set(TASK_APP, APPM_READY);

                // tuya
                LOG_INF("Start adv...");
                ty_ble_start_adv();
            #if (BLE_APP_CENTRAL_SUPPORT)
                app_central_scan_start();
            #endif
            }
        } break;

        case (GAPM_GEN_RAND_NB) :
        {
            LOG_DBG("GAPM_GEN_RAND_NB");
            if (app_env.rand_cnt == 1)
            {
                // Generate a second random number
                app_env.rand_cnt++;
                struct gapm_gen_rand_nb_cmd *cmd = KE_MSG_ALLOC(GAPM_GEN_RAND_NB_CMD,
                                                                TASK_GAPM, TASK_APP,
                                                                gapm_gen_rand_nb_cmd);
                cmd->operation = GAPM_GEN_RAND_NB;
                ke_msg_send(cmd);
            }
            else
            {
                struct gapm_set_irk_cmd *cmd = KE_MSG_ALLOC(GAPM_SET_IRK_CMD,
                                                            TASK_GAPM, TASK_APP,
                                                            gapm_set_irk_cmd);
                app_env.rand_cnt=0;
                cmd->operation = GAPM_SET_IRK;
                memcpy(&cmd->irk.key[0], &app_env.loc_irk[0], KEY_LEN);
                ke_msg_send(cmd);
            }
        } break;

        case (GAPM_SET_IRK):
        {
            LOG_DBG("GAPM_SET_IRK");
            // ASSERT_INFO(param->status == GAP_ERR_NO_ERROR, param->operation, param->status);

            // If not Bonded, store the generated value in NVDS
        #if(BLE_APP_SEC)
            if (app_sec_get_bond_status()==false)
            {
            #if (NVDS_SUPPORT)
                if (nvds_put(NVDS_TAG_LOC_IRK, KEY_LEN, (uint8_t *)&app_env.loc_irk) != NVDS_OK)
            #endif
                {
                    ASSERT_INFO(0, 0, 0);
                }
            }
        #endif

            app_env.rand_cnt = 0;
        } break;

    #if (BLE_APP_PRIVACY)
        case (GAPM_GET_RAL_SIZE):
        case (GAPM_SET_RAL):
            appm_privacy_cmp_evt_handler(msgid, param, dest_id, src_id);
            break;
    #endif

        case (GAPM_CREATE_ADV_ACTIVITY):
        case (GAPM_SET_ADV_DATA):
        case (GAPM_SET_SCAN_RSP_DATA):
            app_adv_cmp_evt_handler((void*)param);
            break;

        case (GAPM_STOP_ACTIVITY):
        case (GAPM_START_ACTIVITY):
        case (GAPM_DELETE_ACTIVITY):
        {
            // Perform next operation
            app_adv_cmp_evt_handler((void*)param);
        #if (BLE_APP_CENTRAL_SUPPORT)
            app_central_update_state(param->operation, 0, param->status);
        #endif
        } break;

    #if (BLE_APP_CENTRAL_SUPPORT)
        case (GAPM_CREATE_SCAN_ACTIVITY):
        case (GAPM_CREATE_INIT_ACTIVITY):
        {
            app_central_update_state(param->operation, 0, param->status);
        } break;
    #endif

        case (GAPM_DELETE_ALL_ACTIVITIES) :
        {
            app_adv_cmp_evt_handler((void*)param);
        #if (BLE_APP_CENTRAL_SUPPORT)
            app_central_update_state(param->operation, 0, param->status);
        #endif
        } break;

        default:
        {
            // Drop the message
        } break;
    }

    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPM_GEN_RAND_NB_IND handler
 *        reception of random number generated indicate
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapm_gen_rand_nb_ind_handler(ke_msg_id_t const msgid, struct gapm_gen_rand_nb_ind *param,
                                        ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
    if (app_env.rand_cnt==1) // First part of IRK
    {
        memcpy(&app_env.loc_irk[0], &param->randnb.nb[0], 8);
    }
    else if (app_env.rand_cnt==2) // Second part of IRK
    {
        memcpy(&app_env.loc_irk[8], &param->randnb.nb[0], 8);
    }

    return KE_MSG_CONSUMED;
}

/**
 ***************************************************************************************************
 * @brief GAPM_MAX_DATA_LEN_IND handler
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapm_gem_max_data_len_ind_handler(ke_msg_id_t const msgid, struct gapm_max_data_len_ind *param,
                                             ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
    LOG_DBG("(gapm) max_tx=%d, max_tx_time=%d, max_rx=%d, max_rx_time=%d",
            param->suppted_max_tx_octets, param->suppted_max_tx_time,
            param->suppted_max_rx_octets, param->suppted_max_rx_time);

    uint8_t conidx = KE_IDX_GET(src_id);

    // tuya
    ty_server_set_data_len(conidx, param->suppted_max_tx_octets);

    return KE_MSG_CONSUMED;
}

/**
 ***************************************************************************************************
 * @brief GAPM_LIST_SIZE_IND handler
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapm_list_size_ind_handler(ke_msg_id_t const msgid, struct gapm_list_size_ind *param,
                                      ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
#if (BLE_APP_WHITE_LIST)
    LOG_DBG("Whitelist size = %d", param->size);
    if (param->operation == GAPM_GET_WLIST_SIZE) {
        appm_whl_set_size(param->size);
    }
#endif
    return KE_MSG_CONSUMED;
}

/**
 ***************************************************************************************************
 * @brief GAPM_DEV_BDADDR_IND handler
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapm_dev_bdaddr_ind_handler(ke_msg_id_t const msgid, struct gapm_dev_bdaddr_ind *param,
                                       ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
    LOG_DBG_ARRAY_EX("Adrr", param->addr.addr.addr, 6);
    return KE_MSG_CONSUMED;
}

/**
 ***************************************************************************************************
 * @brief GAPC_GET_DEV_INFO_REQ_IND handler
 *        reception of random number generated indicate
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_get_dev_info_req_ind_handler(ke_msg_id_t const msgid,
                                             struct gapc_get_dev_info_req_ind const *param,
                                             ke_task_id_t const dest_id,
                                             ke_task_id_t const src_id)
{
    switch(param->req)
    {
        case GAPC_DEV_NAME:
        {
            LOG_DBG("Get device name: %s", APP_DFLT_DEVICE_NAME);
            struct gapc_get_dev_info_cfm * cfm = KE_MSG_ALLOC_DYN(GAPC_GET_DEV_INFO_CFM,
                                                                  src_id, dest_id,
                                                                  gapc_get_dev_info_cfm,
                                                                  APP_DEVICE_NAME_MAX_LEN);
            cfm->req = param->req;
            cfm->info.name.length = strlen(APP_DFLT_DEVICE_NAME);
            memcpy(cfm->info.name.value, APP_DFLT_DEVICE_NAME, cfm->info.name.length);

            // Send message
            ke_msg_send(cfm);
        } break;

        case GAPC_DEV_APPEARANCE:
        {
            LOG_DBG("Get device appearance: %d", CONFIG_BT_DEVICE_APPEARANCE);
            // Allocate message
            struct gapc_get_dev_info_cfm *cfm = KE_MSG_ALLOC(GAPC_GET_DEV_INFO_CFM,
                                                             src_id, dest_id,
                                                             gapc_get_dev_info_cfm);
            cfm->req = param->req;
            cfm->info.appearance = CONFIG_BT_DEVICE_APPEARANCE;

            // Send message
            ke_msg_send(cfm);
        } break;

        case GAPC_DEV_SLV_PREF_PARAMS:
        {
            LOG_DBG("Get device preferable connection parameters: %d/%d/%d/%d", APP_BLE_CONN_INTERVAL_MIN,
                                                                                APP_BLE_CONN_INTERVAL_MAX,
                                                                                APP_BLE_CONN_LATENCY,
                                                                                APP_BLE_CONN_TIMEOUT);
            // Allocate message
            struct gapc_get_dev_info_cfm *cfm = KE_MSG_ALLOC(GAPC_GET_DEV_INFO_CFM,
                                                             src_id, dest_id,
                                                             gapc_get_dev_info_cfm);
            cfm->req = param->req;
            // Slave preferred Connection interval Min
            cfm->info.slv_pref_params.con_intv_min  = APP_BLE_CONN_INTERVAL_MIN;
            // Slave preferred Connection interval Max
            cfm->info.slv_pref_params.con_intv_max  = APP_BLE_CONN_INTERVAL_MAX;
            // Slave preferred Connection latency
            cfm->info.slv_pref_params.slave_latency = APP_BLE_CONN_LATENCY;
            // Slave preferred Link supervision timeout
            cfm->info.slv_pref_params.conn_timeout  = APP_BLE_CONN_TIMEOUT;

            // Send message
            ke_msg_send(cfm);
        } break;

        default:
            break;
    }

    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPC_SET_DEV_INFO_REQ_IND handler
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance (TASK_GAP).
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_set_dev_info_req_ind_handler(ke_msg_id_t const msgid,
                                             struct gapc_set_dev_info_req_ind const *param,
                                             ke_task_id_t const dest_id,
                                             ke_task_id_t const src_id)
{
    // Set Device configuration
    struct gapc_set_dev_info_cfm* cfm = KE_MSG_ALLOC(GAPC_SET_DEV_INFO_CFM,
                                                     src_id, dest_id,
                                                     gapc_set_dev_info_cfm);
    // Reject to change parameters
    cfm->status = GAP_ERR_REJECTED;
    cfm->req = param->req;
    // Send message
    ke_msg_send(cfm);

    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPC_CONNECTION_REQ_IND handler
 *        Handles connection complete event from the GAP. Enable all required profiles
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance (TASK_GAP).
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_connection_req_ind_handler(ke_msg_id_t const msgid,
                                           struct gapc_connection_req_ind const *param,
                                           ke_task_id_t const dest_id,
                                           ke_task_id_t const src_id)
{
    app_env.conidx = KE_IDX_GET(src_id);

    LOG_INF("Connected.");

    // Check if the received Connection Handle was valid
    if (app_env.conidx != GAP_INVALID_CONIDX)
    {
    #if (BLE_APP_CENTRAL_SUPPORT)
        if (param->role == 0)
        {// master
            uint8_t conidx = app_env.conidx;
            app_central_set_conn_handle(conidx, param->conhdl);

        #if (BLE_APP_SEC)
            if (is_bond == false)
            {
                // Ask for the peer device to either start encryption
                app_sec_bond_req(conidx);
            }
            else
        #endif
            {
            #if (BLE_APP_SEC)
                app_sec_encrypt_req(conidx, param->peer_addr);
            #endif
                struct gattc_exc_mtu_cmd * mtu_cmd = KE_MSG_ALLOC_DYN(GATTC_EXC_MTU_CMD,
                                                                      KE_BUILD_ID(TASK_GATTC, conidx),
                                                                      dest_id,
                                                                      gattc_exc_mtu_cmd, 0);

                mtu_cmd->operation = GATTC_MTU_EXCH;

                // Send message
                ke_msg_send(mtu_cmd);
            }
        }
        else 
    #endif
        {
            // Retrieve the connection info from the parameters
            app_env.conhdl = param->conhdl;

            // Send connection confirmation
            struct gapc_connection_cfm *cfm = KE_MSG_ALLOC(GAPC_CONNECTION_CFM,
                                                        KE_BUILD_ID(TASK_GAPC, app_env.conidx),
                                                        TASK_APP,
                                                        gapc_connection_cfm);
        #if(BLE_APP_SEC)
            cfm->auth = GAP_AUTH_REQ_MITM_BOND;
        #else
            cfm->auth = GAP_AUTH_REQ_NO_MITM_NO_BOND;
        #endif
            // Send the message
            ke_msg_send(cfm);

            // We are now in connected State
            ke_state_set(dest_id, APPM_CONNECTED);

            // GAP connected, to do something here
            // tuya
            app_ty_server_enable_prf(app_env.conidx);
            ty_ble_connect_handler();
        }
    }
    else
    {
        // No connection has been established, restart advertising
        LOG_ERR("GAP_INVALID_CONIDX");
    }

    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPC_CMP_EVT handler
 *        Handles GAP controller command complete events.
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance (TASK_GAP).
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_cmp_evt_handler(ke_msg_id_t const msgid,
                                struct gapc_cmp_evt const *param,
                                ke_task_id_t const dest_id,
                                ke_task_id_t const src_id)
{
    switch(param->operation)
    {
        case (GAPC_UPDATE_PARAMS):
        {
            if (param->status != GAP_ERR_NO_ERROR)
            {
            }
        } break;

    #if (BLE_APP_CENTRAL_SUPPORT)
    #if (BLE_APP_SEC_CON)
        case (GAPC_BOND):
        {
            if (param->status == GAP_ERR_NO_ERROR)
            {
                uint8_t conidx = KE_IDX_GET(src_id);
                struct gattc_exc_mtu_cmd * mtu_cmd = KE_MSG_ALLOC_DYN(GATTC_EXC_MTU_CMD,
                                                                      KE_BUILD_ID(TASK_GATTC, conidx),
                                                                      dest_id,
                                                                      gattc_exc_mtu_cmd, 0);
                mtu_cmd->operation = GATTC_MTU_EXCH;

                // Send message
                ke_msg_send(mtu_cmd);
            }
        } break;
    #endif
    #endif

        default:
            break;
    }

    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPC_DISCONNECT_IND handler
 *        Handles disconnection complete event from the GAP.
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance (TASK_GAP).
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_disconnect_ind_handler(ke_msg_id_t const msgid,
                                       struct gapc_disconnect_ind const *param,
                                       ke_task_id_t const dest_id,
                                       ke_task_id_t const src_id)
{
    LOG_INF("Disconnected, reason: 0x%02X", param->reason);

#if (BLE_APP_SEC)
    app_sec_gapc_disconnect_ind_handler(msgid, (void*)param, dest_id, src_id);
#endif

    // Go to the ready state
    ke_state_set(TASK_APP, APPM_READY);

    // GAP disconnected, to do something here
    // tuya
    app_ty_server_disable_prf(KE_IDX_GET(src_id));
    ty_ble_disconnect_handler();

#if (BLE_APP_CENTRAL_SUPPORT)
    uint8_t conidx = KE_IDX_GET(src_id);
    app_central_disconnect(conidx);
#endif

    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPC_PARAM_UPDATE_REQ_IND handler
 *        Handles connect param update(>4.1) event from the GAP.
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance (TASK_GAP).
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_param_update_req_ind_handler(ke_msg_id_t const msgid,
                                             struct gapc_param_update_req_ind const *param,
                                             ke_task_id_t const dest_id,
                                             ke_task_id_t const src_id)
{
    // Prepare the GAPC_PARAM_UPDATE_CMD message
    struct gapc_param_update_cfm *cfm = KE_MSG_ALLOC(GAPC_PARAM_UPDATE_CFM,
                                                     KE_BUILD_ID(TASK_GAPC, app_env.conidx),
                                                     TASK_APP,
                                                     gapc_param_update_cfm);

    // True to accept slave connection parameters, False else.
    cfm->accept = true;
    // Minimum Connection Event Duration
    cfm->ce_len_min = 0x0;
    // Maximum Connection Event Duration
    cfm->ce_len_max = 0xFFFF;

    // Send the message
    ke_msg_send(cfm);

    return (KE_MSG_CONSUMED);
}

/**
 ***************************************************************************************************
 * @brief GAPC_PARAM_UPDATED_IND handler
 *        Handles connect param update(>4.1) event from the GAP.
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance (TASK_GAP).
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
 static int gapc_param_update_ind_handler(ke_msg_id_t const msgid,
                                          struct gapc_param_updated_ind const *param,
                                          ke_task_id_t const dest_id,
                                          ke_task_id_t const src_id)
 {
    // GAP connection parameter updated, to do something here
     
 
    return (KE_MSG_CONSUMED);
 }

/**
 ***************************************************************************************************
 * @brief GAPC_LE_PKT_SIZE_IND handler
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_pkt_size_ind_handler(ke_msg_id_t const msgid, struct gapc_le_pkt_size_ind const *param,
                                     ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
    LOG_INF("max_tx=%d, max_tx_time=%d, max_rx=%d, max_rx_time=%d",
            param->max_tx_octets, param->max_tx_time,
            param->max_rx_octets, param->max_rx_time);

    uint8_t conidx = KE_IDX_GET(src_id);

    // tuya
    ty_server_set_data_len(conidx, param->max_tx_octets);

#if (BLE_APP_CENTRAL_SUPPORT)
    app_central_set_tx_len(conidx, param->max_tx_octets);
#endif

    return KE_MSG_CONSUMED;
}

/**
 ***************************************************************************************************
 * @brief GATTC_MTU_CHANGED_IND handler
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gattc_mtu_changed_ind_handler(ke_msg_id_t const msgid, struct gattc_mtu_changed_ind *param,
                                         ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
    LOG_INF("MTU Exchanged. MTU=%d", param->mtu);
    uint8_t conidx = KE_IDX_GET(src_id);

    // tuya
    ty_server_set_max_mtu(conidx, param->mtu);

#if (BLE_APP_CENTRAL_SUPPORT)
    app_central_set_max_mtu(conidx, param->mtu);
#endif

    return KE_MSG_CONSUMED;
}

/**
 ***************************************************************************************************
 * @brief GAPC_LE_PHY_IND handler
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapc_le_phy_ind_handler(ke_msg_id_t const msgid, struct gapc_le_phy_ind *param,
                                   ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
    LOG_VBS_FUNC();
    LOG_INF("PHY: tx %dM, rx %dM", param->tx_phy, param->rx_phy);

    return (KE_MSG_CONSUMED);
}

#if (BLE_APP_CENTRAL_SUPPORT)
/**
 ***************************************************************************************************
 * @brief Handles GAPM_EXT_ADV_REPORT_IND event.
 *
 * @param[in] msgid     Id of the message received.
 * @param[in] param     Pointer to the parameters of the message.
 * @param[in] dest_id   ID of the receiving task instance.
 * @param[in] src_id    ID of the sending task instance.
 *
 * @return If the message was consumed or not.
 ***************************************************************************************************
 */
static int gapm_ext_adv_report_ind_handler(ke_msg_id_t const msgid,
                                           struct gapm_ext_adv_report_ind const *p_param,
                                           ke_task_id_t const dest_id,
                                           ke_task_id_t const src_id)
{
    LOG_INF("%d", p_param->rssi);
    return (KE_MSG_CONSUMED);
}
#endif

/*
 * GLOBAL VARIABLES DEFINITION
 ***************************************************************************************************
 */
// Default state handlers definition.
KE_MSG_HANDLER_TAB(appm)
{
    // Note: first message is latest message checked by kernel so default is put on top.
    {KE_MSG_DEFAULT_HANDLER,    (ke_msg_func_t)appm_msg_handler},

    // GAPM messages
    {GAPM_PROFILE_ADDED_IND,    (ke_msg_func_t)gapm_profile_added_ind_handler},
    {GAPM_ACTIVITY_CREATED_IND, (ke_msg_func_t)gapm_activity_created_ind_handler},
    {GAPM_ACTIVITY_STOPPED_IND, (ke_msg_func_t)gapm_activity_stopped_ind_handler},
    {GAPM_CMP_EVT,              (ke_msg_func_t)gapm_cmp_evt_handler},
    {GAPM_GEN_RAND_NB_IND,      (ke_msg_func_t)gapm_gen_rand_nb_ind_handler},
    {GAPM_MAX_DATA_LEN_IND,     (ke_msg_func_t)gapm_gem_max_data_len_ind_handler},
    {GAPM_LIST_SIZE_IND,        (ke_msg_func_t)gapm_list_size_ind_handler},
    {GAPM_DEV_BDADDR_IND,       (ke_msg_func_t)gapm_dev_bdaddr_ind_handler},
#if (BLE_APP_CENTRAL_SUPPORT)
    {GAPM_EXT_ADV_REPORT_IND,   (ke_msg_func_t)gapm_ext_adv_report_ind_handler},
#endif

    // GAPC messages
    {GAPC_GET_DEV_INFO_REQ_IND, (ke_msg_func_t)gapc_get_dev_info_req_ind_handler},
    {GAPC_SET_DEV_INFO_REQ_IND, (ke_msg_func_t)gapc_set_dev_info_req_ind_handler},
    {GAPC_CONNECTION_REQ_IND,   (ke_msg_func_t)gapc_connection_req_ind_handler},
    {GAPC_CMP_EVT,              (ke_msg_func_t)gapc_cmp_evt_handler},
    {GAPC_DISCONNECT_IND,       (ke_msg_func_t)gapc_disconnect_ind_handler},
    {GAPC_PARAM_UPDATE_REQ_IND, (ke_msg_func_t)gapc_param_update_req_ind_handler},
    {GAPC_PARAM_UPDATED_IND,    (ke_msg_func_t)gapc_param_update_ind_handler},
    {GAPC_LE_PKT_SIZE_IND,      (ke_msg_func_t)gapc_pkt_size_ind_handler},
    {GATTC_MTU_CHANGED_IND,     (ke_msg_func_t)gattc_mtu_changed_ind_handler},
    {GAPC_LE_PHY_IND,           (ke_msg_func_t)gapc_le_phy_ind_handler},
};

// Defines the place holder for the states of all the task instances.
ke_state_t appm_state[APP_IDX_MAX];

// Application task descriptor
const struct ke_task_desc TASK_DESC_APP = {appm_msg_handler_tab, appm_state, APP_IDX_MAX, ARRAY_LEN(appm_msg_handler_tab)};

/// @} APPTASK
